package com.moss.framework.config;

import com.alibaba.fastjson2.JSON;
import com.moss.common.constant.HttpStatus;
import com.moss.common.domain.AjaxResult;
import com.moss.common.exception.ServiceException;
import com.moss.common.exception.URIPermissionException;
import com.moss.common.exception.UploadImageBedException;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.context.support.DefaultMessageSourceResolvable;
import org.springframework.validation.ObjectError;
import org.springframework.web.HttpMediaTypeNotSupportedException;
import org.springframework.web.HttpRequestMethodNotSupportedException;
import org.springframework.web.bind.MethodArgumentNotValidException;
import org.springframework.web.bind.MissingServletRequestParameterException;
import org.springframework.web.bind.ServletRequestBindingException;
import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.web.bind.annotation.RestControllerAdvice;

import javax.servlet.http.HttpServletRequest;
import java.util.List;
import java.util.Objects;
import java.util.stream.Collectors;


/**
 * 統一异常处理
 */
@RestControllerAdvice
public class GlobalExceptionHandler {


    private static final Logger log = LoggerFactory.getLogger(GlobalExceptionHandler.class);


    /**
     * 处理运行异常
     */
    @ExceptionHandler(RuntimeException.class)
    public AjaxResult<Void> handleRuntimeException(HttpServletRequest request, RuntimeException ex) {
        log.error("异常信息", ex);
        log.error("请求地址：[{}]", request.getRequestURL());
        log.error("请求参数: " + JSON.toJSONString(request.getParameterMap()));
        if (ex instanceof ServiceException){
            return new AjaxResult<>(HttpStatus.ERROR,ex.getMessage());
        }
        if (ex instanceof URIPermissionException){
            return new AjaxResult<>(HttpStatus.UNAUTHORIZED,ex.getMessage());
        }
        return AjaxResult.error();
    }

    /**
     * 处理其他异常
     * 用来捕获404,400 这种无法到达controller的错误,似乎无效
     * 404 被tomcat容器拦截了到不了controller,也就到不了@ControllerAdvice
     * @param request req
     * @param ex ex
     * @return AjaxResult result
     * @throws Exception e
     */
    @ExceptionHandler(value = Exception.class)
    public AjaxResult<String> defaultErrorHandler(HttpServletRequest request, Exception ex) throws Exception {
        log.error(ex.getMessage(), ex);
        log.error("请求地址：[{}]", request.getRequestURL());
        log.error("请求参数:[{}]", JSON.toJSONString(request.getParameterMap()));
        AjaxResult<String> result;
        if (ex instanceof MissingServletRequestParameterException){
            result = new AjaxResult<>(HttpStatus.ERROR,"缺少必要的参数，请检查数据或数据提交方式");
        } else if (ex instanceof ServletRequestBindingException) {
            result = new AjaxResult<>(HttpStatus.ERROR,"缺少必要的参数 - " + ex.getMessage());
        } else if (ex instanceof HttpMediaTypeNotSupportedException){
            result = new AjaxResult<>(HttpStatus.ERROR,"Content type 错误");
        }else if (ex instanceof HttpRequestMethodNotSupportedException) {
            result = new AjaxResult<>(HttpStatus.ERROR,"请求方式不支持 - " + ((HttpRequestMethodNotSupportedException) ex).getMethod());
        } else if (ex instanceof UploadImageBedException){
            result = new AjaxResult<>(HttpStatus.ERROR,"图片上传失败");
        }else if (ex instanceof MethodArgumentNotValidException){
            List<ObjectError> allErrors = ((MethodArgumentNotValidException) ex).getAllErrors();
            String errorMsg = allErrors.stream().map(DefaultMessageSourceResolvable::getDefaultMessage).collect(Collectors.joining(","));
            result = new AjaxResult<>(HttpStatus.ERROR, "缺少必要的参数 - ["+errorMsg+"]");
        }else {
            result = AjaxResult.error();
        }
        return result;
    }
}